package com.hui.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hui.constant.MC;
import com.hui.dto.*;
import com.hui.entity.Emp;
import com.hui.excel.EmpExcel;
import com.hui.exception.IllegalParamException;
import com.hui.exception.ServerErrorException;
import com.hui.exception.VersionException;
import com.hui.mapper.EmpMapper;
import com.hui.service.EmpService;
import com.hui.util.JwtUtil;
import com.hui.util.MinioUtil;
import com.hui.vo.EmpVO;
import com.hui.vo.LoginVO;
import jakarta.annotation.Resource;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
@CacheConfig(cacheNames = "emp")
public class EmpServiceImpl implements EmpService {

    @Resource
    private EmpMapper empMapper;

    @CacheEvict(allEntries = true)
    @Override
    public int insert(EmpInsertDTO dto) {
        String info = dto.getInfo();
        Emp emp = BeanUtil.copyProperties(dto, Emp.class);
        emp.setPassword(SecureUtil.md5(emp.getPassword()));
        emp.setInfo(StrUtil.isBlank(info)?"暂无信息":info);
        emp.setAvatar(MC.Emp.DEFAULT_AVATAR);
        emp.setGender(IdcardUtil.getGenderByIdCard(emp.getIdcard()));
        emp.setAge(IdcardUtil.getAgeByIdCard(emp.getIdcard()));
        emp.setProvince(IdcardUtil.getProvinceByIdCard(emp.getIdcard()));
        emp.setAddress("暂未添加详细地址");
        emp.setCreated(LocalDateTime.now());
        emp.setUpdated(LocalDateTime.now());
        emp.setDeleted(0);
        emp.setVersion(0L);
        int result = empMapper.insert(emp);
        if (result <= 0){
            throw new ServerErrorException("DB添加失败");
        }
        return result;
    }

    @Cacheable(key = "#p0",condition = "#p0 !=null", unless = "#result == null")
    @Override
    public Emp select(Long id) {
        Emp result = empMapper.select(id);
        if (ObjectUtil.isNull(result)){
            throw new ServerErrorException("员工不存在");
        }
        return result;
    }

    @Cacheable(key = "#root.methodName", unless = "#result == null")
    @Override
    public List<EmpVO> list() {
        return empMapper.list(new EmpPageDTO())
                .stream()
                .map(emp -> BeanUtil.copyProperties(emp, EmpVO.class))
                .collect(Collectors.toList());
    }

    @Cacheable(key = "#root.methodName+ ':' + #p0.toString() + ':' + #p0.getPageSize()", condition = "#p0 != null")
    @Override
    public PageInfo<Emp> page(EmpPageDTO dto) {
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        return new PageInfo<>(empMapper.list(dto));
    }

    @CacheEvict(allEntries = true)
    @Transactional
    @Override
    @Retryable(value = VersionException.class)
    public int update(EmpUpdateDTO dto) {
        Long id = dto.getId();
        if (ObjectUtil.isNull(id)){
            throw new IllegalParamException("ID为空");
        }
        Emp emp = empMapper.select(id);
        if (ObjectUtil.isNull(emp)){
            throw new ServerErrorException("记录不存在");
        }
        BeanUtil.copyProperties(dto, emp);
        emp.setUpdated(LocalDateTime.now());
        int result = empMapper.update(emp);
        if (result <= 0){
            throw new VersionException("DB修改失败");
        }
        return result;
    }

    @CacheEvict(allEntries = true)
    @Override
    public int delete(Long id) {
        int result = empMapper.delete(id);
        if (result <= 0){
            throw new ServerErrorException("DB删除失败");
        }
        return result;
    }

    @CacheEvict(allEntries = true)
    @Override
    public int deleteBatch(List<Long> ids) {
        int result = empMapper.deleteBatch(ids);
        if (result <= 0){
            throw new ServerErrorException("DB删除失败");
        }
        return result;
    }

    @Override
    public List<EmpExcel> getExcelData() {
        return empMapper.list(new EmpPageDTO())
                .stream()
                .map(emp -> {
                    EmpExcel empExcel = BeanUtil.copyProperties(emp, EmpExcel.class);
                    if (ObjectUtil.isNotNull(emp.getDept())){
                        empExcel.setDeptName(emp.getDept().getTitle());
                    }
                    empExcel.setGender(MC.Emp.genderFormat(emp.getGender()));
                    return empExcel;
                })
                .collect(Collectors.toList());
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @CacheEvict(allEntries = true)
    @Override
    public String uploadAvatar(MultipartFile newFile, Long id) {
        Emp emp = empMapper.select(id);
        if (ObjectUtil.isNull(emp)){
            throw new ServerErrorException("记录不存在");
        }
        String oldFile = emp.getAvatar();
        String newFileName = MinioUtil.randomFilename(newFile);
        emp.setAvatar(newFileName);
        if (empMapper.update(emp)<= 0){
            throw new ServerErrorException("DB更新失败");
        }

        try {
            //MinIo删除旧文件 （默认文件不删除）
            if (!MC.Emp.DEFAULT_AVATAR.equals(oldFile)) {
                MinioUtil.delete(oldFile, MC.MinIO.AVATAR_DIR, MC.MinIO.BUCKET_NAME);
            }
            //MinIO上传新文件
            MinioUtil.upload(newFile, newFileName, MC.MinIO.AVATAR_DIR, MC.MinIO.BUCKET_NAME);
        } catch (Exception e) {
            throw new ServerErrorException("MinIo操作失败：" + e.getMessage());
        }
        //返回新文件名
        return newFileName;
    }



    @CacheEvict(allEntries = true)
    @Override
    public int updatePassword(EmpUpdatePasswordDTO dto) {
        String newPassword = SecureUtil.md5(dto.getNewPassword());
        String oldPassword = SecureUtil.md5(dto.getOldPassword());
        Long id = dto.getId();
        int result = empMapper.updatePassword(newPassword, oldPassword, id);
        if (result <= 0){
            throw new ServerErrorException("修改密码失败");
        }
        return result;
    }

    @Override
    public LoginVO loginByAccount(LoginDTO dto) {
        String username = dto.getUsername();
        String password = SecureUtil.md5(dto.getPassword());
        Emp emp = empMapper.selectByAccount(username, password);
        if (ObjectUtil.isNull(emp)){
            throw new ServerErrorException("账号或密码有误");
        }
        String token = JwtUtil.build(emp.getId(),emp.getRealname(),emp.getAvatar());
        LoginVO loginVO = new LoginVO();
        loginVO.setToken(token);
        loginVO.setEmp(emp);
        return loginVO;
    }

}
